/**
 * XDF Validate 
 * ------------------------------
 * 
 * - 
 * - 
 * 
 * @author 
 */
package model.validator;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

import org.xml.sax.Attributes;
import automata.Fsa;
import automata.Label;
import automata.State;

import model.constraints.AbstractConstraint;
import model.constraints.inherited.Configuration;
import model.constraints.inherited.ConfigurationSet;
import model.constraints.inherited.Inters;
import model.constraints.synthesized.SyntAttributesXDF;

public class XDFValidate  implements ObserverSaxParser, Serializable  {

	private static final long serialVersionUID = 1L;
	private Configuration conf1;
	private ConfigurationSet confSet1 =  new ConfigurationSet();
	private ConfigurationSet confSetAux = new ConfigurationSet();

	private Vector<ConfigurationSet> confVec = new Vector<ConfigurationSet>();
	private Vector<SyntAttributesXDF> syntVec = new Vector<SyntAttributesXDF>();

	private Stack<Vector<ConfigurationSet>> stackConf= new Stack<Vector<ConfigurationSet>>();
	private Stack<Vector<SyntAttributesXDF>> stackSynt = new Stack<Vector<SyntAttributesXDF>>();

	private int posRight;
	private StringBuffer posSt;
	
	private Vector<Hashtable<String, Hashtable<ArrayList<String>, String>>> htVec = new Vector<Hashtable<String, Hashtable<ArrayList<String>, String>>>();
	private Vector<Hashtable<String,ArrayList<Inters>>> interVec = new Vector<Hashtable<String,ArrayList<Inters>>>();
	private Hashtable<String, ArrayList<String>> htErrors = new Hashtable<String, ArrayList<String>>();
	private AbstractConstraint absconstraint;
	
	public XDFValidate(AbstractConstraint xdf) {
		absconstraint = xdf;
	}

	public void constructorValidate() {
		System.err.println("CRIANDO XDF VALIDATOR!");
		Fsa f = absconstraint.getContextFsa();
		State s = f.get_start_state();
		
		conf1 = new Configuration(s, f, absconstraint);
		
		confSet1 =  new ConfigurationSet();
		confSetAux = new ConfigurationSet();
		confVec = new Vector<ConfigurationSet>();
		syntVec = new Vector<SyntAttributesXDF>();
		stackSynt = new Stack<Vector<SyntAttributesXDF>>();
		htVec = new Vector<Hashtable<String, Hashtable<ArrayList<String>, String>>>();
		interVec = new Vector<Hashtable<String,ArrayList<Inters>>>();
		htErrors = new Hashtable<String, ArrayList<String>>();
		
		confSet1.add(conf1);
		confVec.add(confSet1);
		
		SyntAttributesXDF syntAtt = new SyntAttributesXDF();
		syntVec.add(syntAtt);			
		
		htErrors.put(absconstraint.getNameConstraint(), new ArrayList<String>());//init hash of errors
	
		Hashtable<String, Hashtable<ArrayList<String>, String>> htContextXfd = new Hashtable<String, Hashtable<ArrayList<String>, String>>();
		htVec.add(htContextXfd);
		
		Hashtable<String,ArrayList<Inters>> htIntersXfd = new Hashtable<String,ArrayList<Inters>>();
		interVec.add(htIntersXfd);		
		
		posRight = 0;
     	posSt = new StringBuffer("r");
     	
		System.out.println("Vetor de Intersecoes:"+interVec.toString());

		stackConf.push(confVec);
		stackSynt.push(syntVec);		
	}	
	
	public void startDocument() {}

	public void endDocument() {}
	
	public void startElement(String localName, String rawName, Attributes attrs) {
		
		confSetAux = new ConfigurationSet();
		Label l = new Label(rawName);
		Vector<SyntAttributesXDF> vecSynt = new Vector<SyntAttributesXDF>();
		
		SyntAttributesXDF syntAtt = new SyntAttributesXDF();
		syntAtt.setNodeName(rawName);
		//syntAtt.addC(true);
		vecSynt.add(syntAtt);
		
		posSt.append(".");
		posSt.append(posRight);
		posRight = 0;
		
		//counter++;
		//posSt1.append(counter);
		
		//System.out.println("AQUI"+posSt);		
		//System.out.println("Abertura -> "+rawName+" pos:"+posSt+" vecSynt: "+vecSynt.toString());
		//System.out.println(posSt);
		
		//System.out.println(counter);
		
		confVec = (Vector<ConfigurationSet>) stackConf.peek();//remove vector of ConfigurationSet of stackConf
		Vector<ConfigurationSet> vecAux = new Vector<ConfigurationSet>();//this a new vector auxiliary
		
		for (Iterator<ConfigurationSet> i = confVec.iterator(); i.hasNext();) {//for all constraints do:
			confSet1 = (ConfigurationSet) i.next();
			confSetAux = confSet1.changeConfiguration(l);
			
			vecAux.add(confSetAux);
		}
		
		stackConf.push(vecAux);//insert vector auxiliary in stackConf
		stackSynt.push(vecSynt);//insert vector synthesized
		
		//attributes are already leaves, so they are treated here
		int len = attrs.getLength();
		
		if (len > 0){ //A->data			
			for (int i = 0; i < len; i++) {				
				posSt.append(".");
				posSt.append(posRight);
				posRight++;
				String sa = attrs.getQName(i);
				String sb = (String) attrs.getValue(i);
				
				int j = posSt.lastIndexOf(".");
				
				Label la = new Label(sa);
				vecSynt = (Vector<SyntAttributesXDF>) stackSynt.pop();
				confVec = (Vector<ConfigurationSet>) stackConf.peek();//get element top of stack without remove
				
				for (int k = 0; k < confVec.size(); k++){ //for all keys do:
					Hashtable<String,ArrayList<Inters>> htIntersXfd = interVec.elementAt(k);
					confSet1 = (ConfigurationSet) confVec.elementAt(k);
					confSetAux = confSet1.changeConfiguration(la); 
					confSetAux.keyValidationData(vecSynt, k, sb, posSt.substring(0,j), posSt.toString(), rawName, htIntersXfd);
				}
				
				stackSynt.push(vecSynt);
				posSt.delete(j,posSt.length());
			}
		}
	}
	
	
	public void endElement(String localName, String rawName, String chVal) {
		
		//System.out.println("CLOSING Node name:"+rawName);
		Vector<SyntAttributesXDF> vecSyntAnt;		
		Vector<SyntAttributesXDF> vecSynt;

	    int j = posSt.lastIndexOf(".");
		posRight = Integer.valueOf(posSt.substring(j+1)).intValue();		
		posRight++;		
		
		if(!chVal.isEmpty()) { //A->data
			
			confVec = (Vector<ConfigurationSet>) stackConf.pop();//get lastElement insert of stack
			vecSynt = (Vector<SyntAttributesXDF>) stackSynt.pop();
			vecSyntAnt = (Vector<SyntAttributesXDF>) stackSynt.pop();
			
			for (int k = 0; k < confVec.size(); k++){ //for all keys do
				confSet1 = (ConfigurationSet) confVec.elementAt(k);
				Hashtable<String,ArrayList<Inters>> htIntersXfd = interVec.elementAt(k);
				vecSyntAnt = confSet1.keyValidationData(vecSyntAnt, k, chVal, posSt.substring(0,j), posSt.toString(), rawName, htIntersXfd);
			}
			
			stackSynt.push(vecSyntAnt);
			
		} else { //A->a1,...,an		
			
			// Extraction of values that are at the bottom of the stacks
			confVec = (Vector<ConfigurationSet>) stackConf.pop();
			
			int k;

			vecSynt = (Vector<SyntAttributesXDF>) stackSynt.pop();	
			vecSyntAnt = (Vector<SyntAttributesXDF>) stackSynt.pop();
			
			for (k = 0; k < confVec.size(); k++){ // for each constraint : appropriate validation
				confSet1 = (ConfigurationSet) confVec.elementAt(k);
				Hashtable<String, Hashtable<ArrayList<String>, String>> htContextXfd = (Hashtable<String, Hashtable<ArrayList<String>, String>>) htVec.elementAt(k);
				Hashtable<String,ArrayList<Inters>> htIntersXfd = interVec.elementAt(k);				
				SyntAttributesXDF stH = (SyntAttributesXDF)vecSynt.elementAt(k);
				
		    	vecSyntAnt = confSet1.keyValidationInNode(vecSyntAnt, k, stH, posSt.substring(0,j), posSt.toString(), rawName, htContextXfd, htIntersXfd, htErrors);		    
			}

			System.out.println("Vetor HT:" +htVec.toString());
			System.out.println("Vetor :" +vecSyntAnt.toString());

			stackSynt.push(vecSyntAnt);	

		}
				
		vecSynt=null;
		posSt.delete(j,posSt.length());
	}
	
	/* Get and Set Methods */

	public void setConstraint(Object constraint) {
		absconstraint = (AbstractConstraint) constraint;
	}
	
	public Object getConstraint(){
		return absconstraint;
	}
	
	public Object getResult(){
		return htVec;
	}
	
	public Object getStackSynt(){
		return stackSynt;
	}
	
	public String getErrosConstraint() {
		Enumeration<String> values = htErrors.keys();
		String value;
		String str = "";
		while(values.hasMoreElements()) { 
			value = (String) values.nextElement(); 
			for(String item : htErrors.get(value))
				str += "[" + value + "]: " + item + "\n"; 
		} 			
		
		return str;
	}
	
	public String printConfigurationSet(Object configurationSet)
	{
		ConfigurationSet cs = (ConfigurationSet) configurationSet;
		String confFsa = new String("{");
		
		for (Iterator<Configuration> i = cs.iterator(); i.hasNext();)
		{
			Configuration c = (Configuration) i.next();
			confFsa = confFsa + c.getFsa().toString();
			confFsa = confFsa + c.getState().toString();
			confFsa = confFsa + ",";
		}
		
		confFsa = confFsa + "}";
		//System.out.println(confFsa);
		
		return confFsa;
	}	
}
